﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using NHibernate;
using NHibernate.Criterion;
using NHibernate.Engine;
using NHibernate.SqlCommand;
using NHibernate.Type;
using NHibernate.Util;

namespace TelerikMvcGridCustomBindingHelper.NHibernate.Aggregates
{
    [Serializable]
    public class BetterSqlCriterion : AbstractCriterion
    {
        private readonly string _sql;
        private readonly TypedValue[] _typedValues;

        public BetterSqlCriterion(string sql)
            : this(sql, ArrayHelper.EmptyObjectArray, TypeHelper.EmptyTypeArray) { }

        public BetterSqlCriterion(string sql, object[] values, IType[] types)
        {
            _sql = sql;
            _typedValues = new TypedValue[values.Length];
            for (int i = 0; i < _typedValues.Length; i++)
            {
                _typedValues[i] = new TypedValue(types[i], values[i], EntityMode.Poco);
            }
        }

        /// Render a SqlString for the expression.
        /// A SqlString that contains a valid Sql fragment.
        public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters)
        {
            var properties = Regex.Matches(_sql, @"\{(.*?)\}");

            var sql = _sql;

            foreach (Match property in properties)
            {
                var propertyName = property.Groups[1].Value;

                var columnName = criteriaQuery.GetColumn(criteria, propertyName);
                sql = sql.Replace(property.Value, columnName);
            }

            return SqlString.Parse(sql);
        }

        /// Return typed values for all parameters in the rendered SQL fragment
        /// An array of TypedValues for the Expression.
        public override TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
        {
            return _typedValues;
        }

        /// Return all projections used in this criterion
        /// An array of IProjection used by the Expression.
        public override IProjection[] GetProjections()
        {
            return null;
        }

        /// Gets a string representation of the SQLString.
        /// A String that shows the contents of the SQLString.
        /// This is not a well formed Sql fragment.  It is useful for logging what the looks like.
        public override string ToString()
        {
            return _sql;
        }
    }
}